import { IncomingHttpHeaders, IncomingMessage } from "http";
import tunnel from "tunnel";
import Cookie from "./cookie";
import formData from "form-data";
import fs from "fs";
import { ClientRequest } from "http"
import querystring from "querystring";


export = class RequestOption {

  public static typeof: RequestOption = new RequestOption({});
  /**
   * 表名这是一个附加请求参数
   */
  public $option = false;
  /**
   * 请求地址
   */
  public url: string = "";
  /**
   * 请求方式
   */
  public method?: string;
  /**
   * 请求头
   */
  public headers: IncomingHttpHeaders = {};
  /**
   * 请求参数
   */
  public data: { [key: string]: string } = {};
  /**
   * cookie树，爬虫的利器
   */
  public cookieTree: { [key: string]: any } = {};
  /**
   * 代理
   */
  public proxy?: { host: string, port: number };
  /**
   * 代理 
   */
  public agent?: any;
  /**
   * 请求频率，0的话代表无限制
   */
  public frequency?: number;
  /**
   * 正则频率,如果为true 则进行正则匹配路径查找频率
   */
  public regexFrequency: boolean = false;
  /**
   * cookie对象
   */
  public cookie: typeof Cookie.typeof = new Cookie();
  /**
   * 超时时间，单位为秒
   */
  public timeout?: number;
  /**
   * 是否允许解析返回的数据，如是json则直接序列化为对象 默认不解析
   */
  public parse: boolean = true;
  /**
   * 是否强制序列化，不考虑content-type类型
   */
  public forceDeserialization: boolean = false;
  /**
   * 是否开启多次反序列化
   * 有的一次序列可能不是很彻底，需要多次序列才能序列成功
   */
  public repeatDeserialization: boolean = true;
  /**
   * 是否下载 默认不下载
   */
  public download: boolean = false;
  /**
   * 下载地址
   */
  public saveFilePath?: string;
  /**
   * 下载的文件目录
   */
  public saveFileDir?: string;
  /**
   * 下载的文件名称
   */
  public saveFileName?: string;
  /**
   * 不做任何操纵，返回获取到的req参数
   */
  public original: boolean = false;
  /**
   * 是否开启日志
   */
  public logs: boolean = false;


  constructor(data: { [key: string]: string }) {
    Object.keys(data).forEach(key => {
      if (data[key] != undefined && data[key] != null) {
        // @ts-ignore
        this[key] = data[key]
      }
    })
  }

  public cope(): typeof RequestOption.typeof {
    // 拷贝一份
    let agent = this.agent;
    let cookie = this.cookie.getCookieTree();
    this.agent = undefined;
    this.cookie = undefined as any;
    let info = new RequestOption(JSON.parse(JSON.stringify(this)));
    this.agent = agent;
    this.cookie = new Cookie();
    this.cookie.mergeCookieTree(cookie);
    info.agent = agent;
    info.cookie.mergeCookieTree(cookie);
    return info;
  }

  /**
   * 处理代理
   */
  public handleProxy() {
    // 当代理存在时设置代理
    if (this.proxy) {
      // @ts-ignore
      this.agent = (this.url.startsWith("https") ? tunnel.httpsOverHttp : tunnel.httpOverHttp)({ proxy: this.proxy, rejectUnauthorized: false })
    }
  }


  /**
   * 生成post参数
   */
  public handleParameter(): (req: ClientRequest) => Promise<any> {
    // 处理get参数
    if ((this.method || "").toLocaleLowerCase() === "get") {
      if (this.data && Object.keys(this.data).length) {
        this.url += "?" + querystring.stringify(this.data)
      }
      // 需要发送数据，并且请求不是get
    } else if (this.data) {
      // buffer类型就不需要判断了
      if (this.data instanceof Buffer) {
        let type = this.headers?.["content-type"] || this.headers?.["Content-Type"];
        if (!type) {
          this.headers["content-type"] = "application/json";
        }
        return async (req) => {
          req.write(this.data)
          req.end();
        }
      }
      // 获取发送的类型
      let type = this.headers?.["Content-Type"] || this.headers?.["content-type"] || "application/json";
      switch (type) {
        case "application/x-www-form-urlencoded": {
          return async (req: ClientRequest) => {
            req.write(querystring.stringify(this.data));
            req.end();
          }
        }
        case "application/json": {
          return async (req: ClientRequest) => {
            req.write((typeof this.data === "object") ? JSON.stringify(this.data) : this.data);
            req.end();
          }
        }
        case "multipart/form-data": {
          // 这个数据类型的参数暂时不支持自动生成
          let param = new formData();
          Object.keys(this.data).forEach(key => {
            if (typeof this.data[key] === "string" && fs.existsSync(this.data[key])) {
              param.append(key, fs.createReadStream(this.data[key]))
            } else {
              param.append(key, this.data[key])
            }
          })
          this.headers["content-type"] = "multipart/form-data; boundary=" + param.getBoundary();
          return async (req: ClientRequest) => await new Promise((res, reject) => param.pipe(req).on("finish", res).on("error", reject))
        }
        default: {
          this.headers["content-type"] = "application/json";
          return async (req: ClientRequest) => {
            req.write(typeof this.data === "object" ? JSON.stringify(this.data) : this.data);
            req.end();
          }
        }
      }
    }
    return async (req: ClientRequest) => req.end();
  }

  /**
 * 生成重定向地址
 */
  public generateRedirectAddress(res: IncomingMessage) {
    if (res.headers["location"]?.startsWith("http")) {
      return res.headers["location"];
    } else {
      return (new URL(this.url as string)).origin + res.headers["location"];
    }
  }
}

